package cn.sylinx.hbatis.plugin.ehcache;

import java.util.concurrent.atomic.AtomicBoolean;

import cn.sylinx.hbatis.db.cache.ICacheKit;
import cn.sylinx.hbatis.db.cache.IDataLoader;
import cn.sylinx.hbatis.log.GLog;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

public enum CacheKit implements ICacheKit {

	INSTANCE;

	private CacheManager cacheManager;
	private AtomicBoolean inited = new AtomicBoolean(false);

	public boolean isInited() {
		return inited.get();
	}

	public ICacheKit init(CacheManager cacheManager) {
		this.cacheManager = cacheManager;
		inited.set(true);
		return this;
	}

	public void destory() {
		this.cacheManager = null;
		inited.set(false);
	}

	public CacheManager getCacheManager() {
		return cacheManager;
	}

	public Cache getOrAddCache(String cacheName) {
		Cache cache = cacheManager.getCache(cacheName);
		if (cache == null) {
			synchronized (cacheManager) {
				cache = cacheManager.getCache(cacheName);
				if (cache == null) {
					GLog.info("Could not find cache config [" + cacheName + "], using default.");
					cacheManager.addCacheIfAbsent(cacheName);
					cache = cacheManager.getCache(cacheName);
					GLog.debug("Cache [" + cacheName + "] started.");
				}
			}
		}
		return cache;
	}

	public void put(String cacheName, Object key, Object value) {
		getOrAddCache(cacheName).put(new Element(key, value));
	}

	@SuppressWarnings("unchecked")
	public <T> T get(String cacheName, Object key) {
		Element element = getOrAddCache(cacheName).get(key);
		return element != null ? (T) element.getObjectValue() : null;
	}

	@SuppressWarnings("unchecked")
	public <T> T get(String cacheName, Object key, IDataLoader<?> dataLoader) {
		Object data = get(cacheName, key);
		if (data == null) {
			data = loadAndGet(cacheName, key, dataLoader);
		}
		return (T) data;
	}

	@SuppressWarnings("unchecked")
	private synchronized <T> T loadAndGet(String cacheName, Object key, IDataLoader<?> dataLoader) {
		Object data = get(cacheName, key);
		if (data == null) {
			data = dataLoader.load();
			put(cacheName, key, data);
		}
		return (T) data;
	}
}
